package com.grj.parking.a.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.grj.parking.a.*;
import com.grj.parking.aa.ParkingStrategy;
import com.grj.parking.aa.ParkingStrategyFactory;
import com.grj.parking.config.CacheConstants;
import com.grj.parking.config.MultiLevelCacheService;
import com.grj.parking.domain.*;
import com.grj.parking.mapper.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;


@Slf4j
@Service
@RequiredArgsConstructor
public class ParkingServiceImpl  implements ParkingService {

    private final BlacklistMapper blacklistMapper;
    private final VehicleMapper vehicleMapper;
    private final ParkingRecordMapper parkingRecordMapper;
    private final ParkingSpaceMapper parkingSpaceMapper;
    private final ParkingLotMapper parkingLotMapper;
    private final MultiLevelCacheService multiLevelCacheService;
    private final RabbitTemplate rabbitTemplate;
    private final ParkingFeeRuleMapper parkingFeeRuleMapper;
    private final PaymentRecordMapper paymentRecordMapper;

    private final ParkingStrategyFactory strategyFactory;


    @Override
    public void checkParkingLot(Long lotId) throws Exception {
        ParkingLot parkingLot = multiLevelCacheService.getCache(CacheConstants.CACHE_KEY_PREFIX + lotId, ParkingLot.class, CacheConstants.CACHE_TYPE_PARKING_LOT);
        if (parkingLot == null) {
            parkingLot = parkingLotMapper.selectById(lotId);
            multiLevelCacheService.setCache(CacheConstants.CACHE_KEY_PREFIX + lotId, parkingLot, CacheConstants.CACHE_TYPE_PARKING_LOT);
        }
        if (parkingLot == null) {
            log.error("停车场不存在");
            throw new Exception("停车场不存在");
        }
        if (parkingLot.getStatus() != 1) {
            log.error("停车场已关闭");
            throw new Exception("停车场已关闭");
        }
    }

    @Override
    public Vehicle checkPlate(String carNum) throws Exception {
        Blacklist blacklist = multiLevelCacheService.getCache(carNum, Blacklist.class, CacheConstants.CACHE_TYPE_BLACKLIST);
        if (blacklist != null) {
            log.error("车辆在黑名单中");
            throw new Exception("车辆在黑名单中");
        }
        Vehicle vehicle = multiLevelCacheService.getCache(carNum, Vehicle.class, CacheConstants.CACHE_TYPE_VEHICLE);
        if (vehicle == null) {
            vehicle = vehicleMapper.selectOne(new LambdaQueryWrapper<Vehicle>().eq(Vehicle::getLicensePlate, carNum));
            if (vehicle == null) {
                log.info("车辆不存在: {}", carNum);
                throw new RuntimeException("车辆不存在");
            }
            multiLevelCacheService.setCache(carNum, vehicle, CacheConstants.CACHE_TYPE_VEHICLE);
        }
        return vehicle;

    }

    @Override
    public void checkOrder(String carNum) {
        ParkingRecord parkingRecord = parkingRecordMapper.selectOne(new LambdaQueryWrapper<ParkingRecord>().eq(ParkingRecord::getLicensePlate, carNum));
        if (parkingRecord != null) {
            log.info("存在未结算订单: {}", carNum);
            throw new RuntimeException("存在未结算订单");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void allocateParkingSpace(Long lotId, Vehicle vehicle) {
        ParkingSpace parkingSpace = parkingSpaceMapper.allocateParkingSpace(lotId, vehicle.getVehicleType());
        if (parkingSpace == null){
            log.info("停车场已满: {}", lotId);
            throw new RuntimeException("停车场已满");
        }
        log.info("车位分配成功: {}", parkingSpace);
        int updateCount = parkingLotMapper.decreaseAvailableSpace(lotId);
        if (updateCount != 1){
            log.info("停车场已满: {}", lotId);
            throw new RuntimeException("停车场已满");
        }
        log.info("开闸");

//        rabbitTemplate.convertAndSend("parking.exchange", "parking.queue", parkingSpace);

//        ParkingRecord parkingRecord = new ParkingRecord();
//        parkingRecord.setTenantId(1L);
//        parkingRecord.setRecordNo(UUID.randomUUID().toString());
//        parkingRecord.setSpaceNumber(parkingSpace.getSpaceNumber());
//        parkingRecord.setLotId(lotId);
//        parkingRecord.setSpaceId(parkingSpace.getId());
//        parkingRecord.setLicensePlate(vehicle.getLicensePlate());
//        parkingRecord.setVehicleType(vehicle.getVehicleType().toString());
//        parkingRecord.setEntryTime(new Date());
//        parkingRecord.setEntryImage("entry.jpg");
//        parkingRecord.setStatus(1);
//        parkingRecord.setCreateTime(new Date());
//        int insert = parkingRecordMapper.insert(parkingRecord);
//        if (insert == 0) {
//            log.error("车辆进场失败: licensePlate={}", vehicle.getLicensePlate());
//        }
//        log.info("车辆进场记录: {}", parkingRecord);

    }

    @Override
    public ParkingRecord checkEntryOrder(String carNum) throws Exception {
        log.error("车辆进场中: licensePlate={}", carNum);
        ParkingRecord parkingRecord = parkingRecordMapper.selectOne(new LambdaQueryWrapper<ParkingRecord>().eq(ParkingRecord::getLicensePlate, carNum));
        if (parkingRecord == null) {
            log.error("车辆未进场: licensePlate={}", carNum);
            throw new Exception("车辆未进场");
        }
        log.info("车辆已进场: {}", parkingRecord);
        return parkingRecord;
    }

    @Override
    public ParkingRecord calculateParkingFees(ParkingRecord parkingRecord) {
        // 1.获取计费规则
        ParkingFeeRule parkingFeeRule = parkingFeeRuleMapper.selectOne(new LambdaQueryWrapper<ParkingFeeRule>().eq(ParkingFeeRule::getLotId, parkingRecord.getLotId()).eq(ParkingFeeRule::getSpaceType, parkingRecord.getVehicleType()).eq(ParkingFeeRule::getStatus, 1));
        log.info("计费规则: {}", parkingFeeRule);
        // 2.计算停车时长
        Date now = new Date();
        long duration = now.getTime() - parkingRecord.getEntryTime().getTime();
        long hours = duration / 1000 / 60 / 60;
        parkingRecord.setDuration(BigDecimal.valueOf(duration));
        log.info("停车时长: {}", duration);
        // 3.计算停车费
        BigDecimal firstHourFee = parkingFeeRule.getFirstHourFee();
        BigDecimal parkingFees = BigDecimal.valueOf(hours-1).multiply(parkingFeeRule.getAfterFirstFee());
        parkingFees = parkingFees.add(firstHourFee);
        parkingFees = parkingFees.setScale(2, RoundingMode.HALF_UP);
        parkingRecord.setExitTime(new Date());
        parkingRecord.setAmount(parkingFees);
        parkingRecord.setActualAmount(parkingFees);
        parkingRecord.setDiscountAmount(BigDecimal.ZERO);
        parkingRecord.setPaymentStatus(1);
        parkingRecord.setStatus(1);
        log.info("停车费：{}", parkingFees);
        return parkingRecord;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void issueOpenGateCommand(ParkingRecord parkingRecord) {
        log.info("下发开闸指令成功：{}", parkingRecord);
        parkingRecordMapper.updateById(parkingRecord);
        log.info("更新出场记录成功：{}", parkingRecord);
        ParkingSpace parkingSpace = new ParkingSpace();
        parkingSpace.setId(parkingRecord.getSpaceId());
        parkingSpace.setStatus(1);
        parkingSpaceMapper.updateById(parkingSpace);
        log.info("更新车位成功：{}", parkingSpace);
        parkingLotMapper.increaseAvailableSpace(parkingRecord.getLotId());
        log.info("更新停车场成功：{}", parkingRecord.getLotId());

        // 如果是临时车
        // 如果是月租车
        // 如果是特权车

//        PaymentRecord paymentRecord = new PaymentRecord();
//        paymentRecord.setTenantId(parkingRecord.getTenantId());
//        paymentRecord.setAmount(parkingRecord.getActualAmount());
//        paymentRecord.setStatus(1);
//        paymentRecord.setOperator(parkingRecord.getOperator());
//        paymentRecord.setRecordId(parkingRecord.getId());
//        paymentRecord.setStatus(1);
//        paymentRecordMapper.updateById(paymentRecord);
//        log.info("更新支付成功：{}", paymentRecord);
//        rabbitTemplate.convertAndSend("parking.exchange", "parking.queue", parkingRecord);

    }


}
